package com.bianmaba.controllers.datacollection;

import com.bianmaba.beans.datacollection.CollectionTask;
import com.bianmaba.beans.datacollection.TaskInstance;
import com.bianmaba.beans.datacollection.TaskRunLog;
import com.bianmaba.commons.bean.result.OperationResult;
import com.bianmaba.jobs.CollectionJob;
import com.bianmaba.jobs.supports.CollectionRequest;
import com.bianmaba.jobs.supports.CollectionResult;
import com.bianmaba.jobs.supports.JobParameter;
import com.bianmaba.services.datacollection.CollectionTaskService;
import com.bianmaba.services.datacollection.TaskInstanceService;
import com.bianmaba.services.datacollection.TaskRunLogWriter;
import com.bianmaba.services.datacollection.quartiz.QuartzTaskManager;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.util.*;

@RestController
@RequestMapping(value = "datacollection/job")
public class JobController {
    private static Logger LOG = LoggerFactory.getLogger(JobController.class);
    @Autowired
    private QuartzTaskManager quartzTaskManager;
    @Autowired
    private TaskInstanceService taskInstanceService;
    @Autowired
    private CollectionTaskService collectionTaskService;
    @Autowired
    protected RestTemplate restTemplate;
    @Autowired
    protected TaskRunLogWriter logWriter;

    @RequestMapping("add")
    public boolean add(String name, String group, String classPath) throws ClassNotFoundException, SchedulerException {
        Class clazz = Class.forName(classPath);
        JobDataMap data = new JobDataMap();
        data.put("description", "add Job is running...");
        quartzTaskManager.addJob(clazz, name, group, data, true, true);
        return true;
    }

    @RequestMapping("delete")
    public boolean delete(String name, String group) throws ClassNotFoundException, SchedulerException {
        quartzTaskManager.deleteJob(name, group);
        return true;
    }

    @RequestMapping("trigger")
    public boolean trigger(String name, String group) throws ClassNotFoundException, SchedulerException {
        quartzTaskManager.triggerJob(name, group);
        return true;
    }

    @RequestMapping("schedule")
    public Trigger schedule(String name, String group, String cronExpression) throws ClassNotFoundException {
        Class clazz = Class.forName("com.bianmaba.jobs.DefaultJob");
        JobDataMap data = new JobDataMap();
        data.put("description", "scheduleJob is running...");

        return quartzTaskManager.scheduleJob(clazz, name, group, cronExpression, data);
    }

    @RequestMapping("pause")
    public void pause(String name, String group) throws ClassNotFoundException, SchedulerException {
        quartzTaskManager.pauseJob(name, group);
    }

    @RequestMapping("resume")
    public void resume(String name, String group) throws ClassNotFoundException, SchedulerException {
        quartzTaskManager.resumeJob(name, group);
    }

    @RequestMapping("reschedule")
    public Trigger reschedule(String name, String group, String cronExpression) throws ClassNotFoundException {
        return quartzTaskManager.rescheduleJob(name, group, "0/5 * * * * ?");
    }

    @RequestMapping("stop_job")
    public Boolean stopJob(String taskInstanceId) throws SchedulerException, InterruptedException {
        TaskInstance taskInstance = taskInstanceService.findOne(taskInstanceId);

        String url = taskInstance.getCollectionTask().getCollectionInterface().getBaseUrl() + "stop";
        sendStopRequest(url, taskInstanceId);
//        quartzTaskManager.deleteJob(jobName, jobGroup);
//
        return true;
    }

    protected boolean sendStopRequest(String url, String taskInstanceId) throws InterruptedException {
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        Map<String, String> requestParameter = new HashMap() {{
            put("taskInstanceId", taskInstanceId);
        }};
        HttpEntity<Map> entity = new HttpEntity(requestParameter, headers);
        ResponseEntity<OperationResult> responseEntity = null;
        try {
            responseEntity = restTemplate.postForEntity(url, entity, OperationResult.class);
            OperationResult<Boolean> result = responseEntity.getBody();
            logWriter.putLog(TaskRunLog.of(taskInstanceId, result.getResult(), Calendar.getInstance().getTime()));
            if (!result.isSuccess() || !result.getData()) {
                return false;
            }
            return true;
        } catch (HttpClientErrorException e) {
            int code = e.getRawStatusCode();
            String error = e.getLocalizedMessage();
            if (code == 401) {
                error = "采集请求失败，目标地址未经授权访问或由于凭据无效被拒绝：";
            } else if (code == 403) {
                error = "采集请求失败，目标地址未经授权，请联系管理员：";
            } else if (code == 404) {
                error = "采集请求失败，目标地址不存在请联系管理员：";
            } else if (code == 405) {
                error = "采集请求失败，请求方式（Method）不受支持，请联系管理员：";
            } else if (code == 500) {
                error = "采集请求失败，采集服务出现内部错误，请联系管理员：";
            }
            error = error + String.format("【statusCode=%d,URL=%s,parameters=%s】", code, url, requestParameter.toString());
            LOG.error(error, e);
            logWriter.putLog(TaskRunLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));

        } catch (ResourceAccessException e) {
            String error = "采集请求失败，服务器未开启，请联系管理员：";
            error = error + String.format("【URL=%s,parameters=%s】", url, requestParameter.toString());
            LOG.error(error, e);
            logWriter.putLog(TaskRunLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
        } catch (Exception e) {
            String error = "采集请求失败，采集出现未知异常，请联系管理员：";
            error = error + String.format("【URL=%s,parameters=%s】", url, requestParameter.toString());
            LOG.error(error, e);
            logWriter.putLog(TaskRunLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
        }
        return false;
    }

    @RequestMapping("execute_once")
    public Trigger executeOnce(String taskId) throws ClassNotFoundException {
        CollectionTask task = collectionTaskService.findOne(taskId);
        TaskInstance instance = new TaskInstance(task.getName(), task.getProjectId(), new Date(), null, TaskInstance.Status.WAIT.getIndex(), "执行人", task);
        instance = taskInstanceService.save(instance);
        Class clazz = Class.forName("com.bianmaba.jobs.CollectionJob");

        JobDataMap data = new JobDataMap();
        data.put(JobParameter.PROJECT_ID.getName(), task.getProjectId());
        data.put(JobParameter.TASK_ID.getName(), taskId);
        data.put(JobParameter.TASK_INSTANCE_ID.getName(), instance.getId());
        data.put(JobParameter.COLLECTION_PARAMETERS.getName(), task.getParameterMap());
        data.put(JobParameter.DESCRIPTION.getName(), "execute_once is running...");
        String jobName = instance.getId();
        String jobGroup = task.getProjectId();
        return quartzTaskManager.executeOnceJob(clazz, jobName, jobGroup, data);
    }
}
